package cn.b.sky.user.service.impl;

import cn.b.sky.common.exception.InfoException;
import cn.b.sky.common.utils.EncryptAlgorithm;
import cn.b.sky.user.dao.LoginLogDao;
import cn.b.sky.user.dao.SecurityDao;
import cn.b.sky.user.service.SecurityService;
import cn.b.sky.user.service.UserService;
import cn.b.sky.user.service.model.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Service("securityService")
public class SecurityServiceImpl implements SecurityService {
  private static final Logger log = LoggerFactory.getLogger(SecurityServiceImpl.class);

  private final Map<String, Token> tokens = new HashMap<String, Token>();

  @Resource
  private SecurityDao securityDao;

  @Resource
  private LoginLogDao loginLogDao;

  @Resource
  UserService userService;

  @Override
  public List<MenuUrl> listMenuUrl(String resourceTypeECode) {
    return securityDao.listMenuUrl(resourceTypeECode);
  }

  @Override
  public List<MenuInfo> listMenuByUsername(String username) {
    return securityDao.listMenuByUsername(username);
  }

  @Override
  public UserInfo loadUserByUsername(String username) {
    return securityDao.loadUserByUsername(username);
  }

  @Override
  public List<PermissionInfo> listPermission(String siteCode, String userCode, String languageCode) {
    return securityDao.listPermission(siteCode, userCode, languageCode);
  }

  @Override
  public UserInfo loadUser(String siteCode, String userCode) {
    if (StringUtils.isEmpty(siteCode) || StringUtils.isEmpty(userCode)) {
      return null;
    }
    //超级管理员用户验证
    if(UserInfo.ADMINISTRATOR.equalsIgnoreCase(userCode)){
      return securityDao.loadAdministrator(userCode.trim().toUpperCase());
    }
    return securityDao.loadUser(siteCode.trim().toUpperCase(), userCode.trim().toUpperCase());
  }

  @Override
  public Token login(String siteCode, String userCode, String password, String languageCode, String ipAddress,
      String macAddress) {
    try {
      password = EncryptAlgorithm.hexMD5(password);
    } catch (Exception e) {
      log.error("{}", e);
      return null;
    }

    UserInfo user = securityDao.login(siteCode, userCode, password);
    if (null == user) {
      return null;
    }

    Token token = new Token();
    token.setSiteCode(siteCode);
    token.setUserCode(userCode);
    token.setLanguageCode(languageCode);
    token.setIpAddress(ipAddress);
    token.setLastAccessDateTime(new Date());
    token.setTimeZoneCode(user.getTimeZoneCode());
    token.setToken(newToken());
    tokens.put(token.getToken(), token);

    LoginLog log = new LoginLog();
    log.setSessionId(token.getToken());
    log.setLoginDateTime(new Date());
    log.setSiteCode(siteCode);
    log.setUserCode(userCode);
    log.setUserText(user.getUserText());
    log.setStatus("OK");
    log.setIpAddress(ipAddress);
    log.setMacAddress(macAddress);
    log.setMacAddress(macAddress);

    loginLogDao.insertLog(log);
    return token;
  }

  private String newToken() {
    int hash = UUID.randomUUID().toString().hashCode();
    return String.valueOf(hash);
  }

  @Override
  public Token validateToken(String token) {
    if (!tokens.containsKey(token)) {
      return null;
    }
    Token tokenObj = tokens.get(token);
    boolean valid = !tokenObj.isTimeOut();
    tokenObj.setLastAccessDateTime(new Date());
    return valid ? tokenObj : null;

  }

  @Override
  public Token validateClient(String ipAddress) {
    Token t = getTokenByIpAddress(ipAddress);
    if (null == t) {
      return null;
    }
    return validateToken(t.getToken());
  }

  private Token getTokenByIpAddress(String ipAddress) {
    for (Token t : tokens.values()) {
      if (t.getIpAddress().equalsIgnoreCase(ipAddress)) {
        return t;
      }
    }
    return null;
  }

  @SuppressWarnings("unused")
  private void removeTokensByIpAddress(String ipAddress) {
    for (Token t : tokens.values()) {
      if (t.getIpAddress().equalsIgnoreCase(ipAddress)) {
        tokens.remove(t.getToken());
      }
    }
  }

  @Override
  public void logout(String token) {
    Token tokenOjb = tokens.get(token);
    if (null != tokenOjb) {
      tokens.remove(token);

      LoginLog log = new LoginLog();
      log.setSessionId(tokenOjb.getToken());
      log.setLogoutDateTime(new Date());
      loginLogDao.updateLog(log);
    }
  }

  @Override
  public void appChangePassword(String siteCode, String userCode, String newPassword) {
    try {
      userService.updateUserPwd(siteCode, userCode, EncryptAlgorithm.hexMD5(newPassword));
    } catch (NoSuchAlgorithmException e) {
      throw new InfoException(e);
    } catch (UnsupportedEncodingException e) {
      throw new InfoException(e);
    }

  }

  @Override
  public boolean checkPassword(String siteCode, String userCode, String password) {
    try {
      UserInfo u = userService.selectUser(siteCode, userCode);
      if (EncryptAlgorithm.hexMD5(password).equals(u.getPassword())) {
        return true;
      }
      return false;
    } catch (Exception e) {
      log.error("{}", e);
    }
    return false;
  }

  @Override
  public boolean checkSiteIsLocked(String siteCode) {

    Integer lockFlag = securityDao.selectSiteLocked(siteCode);
    //0--未锁定 1--锁定,为空也是表示工厂不存在，同理返回锁定
    return lockFlag == null ? true : lockFlag != 0;
  }

}
